import { body, param, query } from 'express-validator';
import { validate } from '../validation';
import { AuditAction, EntityType } from '../../types/audit';
import { Request } from 'express';

interface DateValidationRequest extends Request {
  query: {
    startDate?: string;
    endDate?: string;
  }
}

export const auditLogValidator = {
  create: validate([
    body('action')
      .isIn(Object.values(AuditAction))
      .withMessage(`Action must be one of: ${Object.values(AuditAction).join(', ')}`),
    body('entityType')
      .isIn(Object.values(EntityType))
      .withMessage(`Entity type must be one of: ${Object.values(EntityType).join(', ')}`),
    body('entityId')
      .isString()
      .trim()
      .notEmpty()
      .withMessage('Entity ID is required'),
    body('userId')
      .isInt({ min: 1 })
      .withMessage('User ID must be a positive integer'),
    body('details')
      .optional()
      .isObject()
      .withMessage('Details must be an object'),
    body('metadata')
      .optional()
      .isObject()
      .custom((value) => {
        const allowedFields = ['ipAddress', 'userAgent', 'path', 'method', 'timestamp'];
        const invalidFields = Object.keys(value || {}).filter(key => !allowedFields.includes(key));
        if (invalidFields.length > 0) {
          throw new Error(`Invalid metadata fields: ${invalidFields.join(', ')}`);
        }
        if (value?.timestamp && !isValidDate(value.timestamp)) {
          throw new Error('Invalid timestamp format');
        }
        return true;
      })
      .withMessage('Invalid metadata format')
  ]),

  getOne: validate([
    param('id')
      .isString()
      .trim()
      .notEmpty()
      .withMessage('Invalid audit log ID')
  ]),

  list: validate([
    query('page')
      .optional()
      .isInt({ min: 1 })
      .withMessage('Page must be a positive integer'),
    query('limit')
      .optional()
      .isInt({ min: 1, max: 100 })
      .withMessage('Limit must be between 1 and 100'),
    query('action')
      .optional()
      .isIn(Object.values(AuditAction))
      .withMessage(`Action must be one of: ${Object.values(AuditAction).join(', ')}`),
    query('entityType')
      .optional()
      .isIn(Object.values(EntityType))
      .withMessage(`Entity type must be one of: ${Object.values(EntityType).join(', ')}`),
    query('userId')
      .optional()
      .isInt({ min: 1 })
      .withMessage('User ID must be a positive integer'),
    query('startDate')
      .optional()
      .isISO8601()
      .toDate()
      .withMessage('Start date must be a valid ISO 8601 date'),
    query('endDate')
      .optional()
      .isISO8601()
      .toDate()
      .withMessage('End date must be a valid ISO 8601 date')
      .custom((value, { req }) => {
        const request = req as DateValidationRequest;
        if (request.query.startDate && new Date(value) < new Date(request.query.startDate)) {
          throw new Error('End date must be after start date');
        }
        return true;
      })
  ])
};

function isValidDate(value: any): boolean {
  if (!value) return false;
  const date = new Date(value);
  return date instanceof Date && !isNaN(date.getTime());
}
